package ee.homework.fourth;

import java.io.File;

/**
 * Traverses in depth-first first manner through filesystem
 * 
 * @author Kaarel
 * @since 15.03.2011
 */
public class DirectoryTreeTraversal {

	private long maxDirSize;
	private String maxDir;

	public static void main(String[] args) {
		new DirectoryTreeTraversal().run();
	}

	public void run() {
		File cwd = new File(".");
		System.out.println(cwd.getAbsolutePath());
		long dirSize = traverse(cwd, "");
		System.out.println("Size: " + dirSize);
		System.out.println("Max dir: " + maxDir + ", size: " + maxDirSize);
		System.out.println("Depth: " + (getMaxDepth(cwd) + 1));
		for (int i = 1; i <= getMaxDepth(cwd) + 1; i++) {
			System.out.println("Level: " + i + ", filecount: "
					+ getWidth(cwd, 1, i) + ", levelSize: "
					+ getLevelSize(cwd, 1, i));
		}
	}

	public long traverse(File directory, String ident) {
		File[] files = getSortedDirList(directory.listFiles());
		long dirSize = 0;
		for (File file : files) {
			if (file.isDirectory()) {
				long size = traverse(file, ident + "  ");
				if (maxDirSize < size) {
					maxDirSize = size;
					maxDir = file.getAbsolutePath();
				}
			} else {
				dirSize += file.length();
			}
		}
		return dirSize;
	}

	public int getMaxDepth(File directory) {
		File[] files = getSortedDirList(directory.listFiles());
		int depth = 0;
		boolean isDir = false;
		for (File file : files) {
			if (file.isDirectory()) {
				isDir = true;
				int d = getMaxDepth(file);
				if (depth < d) {
					depth = d;
				}
			}
		}
		return isDir ? depth + 1 : 0;
	}

	public long getWidth(File directory, int initial, int level) {
		File[] files = getSortedDirList(directory.listFiles());
		long width = 0;
		if (initial == level) {
			return files.length;
		} else {
			for (File file : files) {
				if (file.isDirectory()) {
					width += getWidth(file, initial + 1, level);
				}
			}
		}
		return width;
	}

	public long getLevelSize(File directory, int initial, int level) {
		File[] files = getSortedDirList(directory.listFiles());
		long size = 0;
		if (initial == level) {
			return getSizeOfDir(files);
		} else {
			for (File file : files) {
				if (file.isDirectory()) {
					size += getLevelSize(file, initial + 1, level);
				}
			}
		}
		return size;
	}

	public long getSizeOfDir(File[] files) {
		int size = 0;
		for (File file : files) {
			if (file.isFile()) {
				size += file.length();
			}
		}
		return size;
	}

	/**
	 * Sorts array of files, so that directorys would be before files
	 * 
	 * @param unsorted
	 * @return
	 */
	public File[] getSortedDirList(File[] unsorted) {
		try {
			for (int i = 0; i < unsorted.length; i++) {
				if (unsorted[i].isFile()) {
					for (int j = i + 1; j < unsorted.length; j++) {
						if (unsorted[j].isDirectory()) {
							File tmp = unsorted[i];
							unsorted[i] = unsorted[j];
							unsorted[j] = tmp;
							break;
						}
					}
				}
			}
		} catch (NullPointerException e) {
			unsorted = new File[0];
		}
		return unsorted;
	}
}
